package com.xinqi.modules.prepare.prepare.manager.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xinqi.common.core.utils.MessageUtils;
import com.xinqi.common.base.current.Currents;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.utils.lambda.Lambdas;
import com.xinqi.common.mybatis.data.service.impl.BaseServiceImpl;
import com.xinqi.modules.prepare.common.constant.PrepareConstant;
import com.xinqi.modules.prepare.common.domain.PrepareBaseParam;
import com.xinqi.modules.prepare.common.dto.UserBaseInfoDO;
import com.xinqi.modules.prepare.common.manager.PrepareCommonManager;
import com.xinqi.modules.prepare.prepare.domain.PrepareEntity;
import com.xinqi.modules.prepare.prepare.domain.PrepareMemberEntity;
import com.xinqi.modules.prepare.prepare.domain.PrepareOperateLogEntity;
import com.xinqi.modules.prepare.prepare.dto.req.PrepareOperateLogQueryDTO;
import com.xinqi.modules.prepare.prepare.dto.rsp.PrepareOperateLogResultDTO;
import com.xinqi.modules.prepare.prepare.enums.PrepareMemberRoleEnum;
import com.xinqi.modules.prepare.prepare.enums.PrepareOperateLogEnum;
import com.xinqi.modules.prepare.prepare.enums.PrepareOperateTypeEnum;
import com.xinqi.modules.prepare.prepare.enums.PrepareSubOperateTypeEnum;
import com.xinqi.modules.prepare.prepare.enums.PrepareTypeEnum;
import com.xinqi.modules.prepare.prepare.manager.PrepareOperateLogManager;
import com.xinqi.modules.prepare.prepare.mapper.PrepareOperateLogMapper;
import com.xinqi.modules.prepare.question.domain.PrepareQuestionBankEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 备课区操作记录表管理层实现
 *
 * @author: system
 * @date: 2023/03/19
 */
@Service
@RequiredArgsConstructor
public class PrepareOperateLogManagerImpl extends BaseServiceImpl<PrepareOperateLogMapper, PrepareOperateLogEntity> implements PrepareOperateLogManager {
    private final PrepareCommonManager commonManager;

    /**
     * 自定义分页查询
     */
    @Override
    public Page<PrepareOperateLogResultDTO> findPage(Page<Object> page, PrepareOperateLogQueryDTO query) {
        return this.baseMapper.findPage(page, query);
    }

    /**
     * 自定义列表查询
     */
    @Override
    public List<PrepareOperateLogResultDTO> findList(PrepareOperateLogQueryDTO query) {
        return this.baseMapper.findList(query);
    }

    /**
     * 根据id查询 备课区操作记录表数据
     */
    @Override
    public PrepareOperateLogEntity findById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return getById(id);
    }

    /**
     * 根据id删除 备课区操作记录表数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return this.removeById(id);
    }

    /**
     * 添加文件操作日志
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addFileOperateLog(PrepareBaseParam prepareBase,
                                     PrepareOperateTypeEnum operateType,
                                     PrepareSubOperateTypeEnum operateSubType) {
        return addFileOperateLog(
            prepareBase.getPrepareId(), prepareBase.getPrePareType(), Currents.userId(),
            operateType, operateSubType, prepareBase.getId(), prepareBase.getName());
    }

    /**
     * 添加文件操作日志
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addFileOperateLog(PrepareBaseParam prepareBase,
                                     PrepareOperateLogEnum operateType) {
        return addFileOperateLog(
            prepareBase.getPrepareId(), prepareBase.getPrePareType(), Currents.userId(),
            operateType.getType(), operateType.getSubType(), prepareBase.getId(), prepareBase.getName());
    }

    /**
     * 添加文件操作日志
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addFileOperateLog(Long prepareId,
                                     PrepareTypeEnum type,
                                     Long operator,
                                     PrepareOperateTypeEnum operateType,
                                     PrepareSubOperateTypeEnum operateSubType,
                                     Long targetId,
                                     String targetName) {
        return addLog(
            prepareId, type,
            operator, operateType, operateSubType,
            targetId, targetName, null, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addMemberOperateLog(PrepareMemberEntity member, PrepareOperateLogEnum logEnum, PrepareMemberRoleEnum beforeRole, PrepareMemberRoleEnum afterRole) {
        return addMemberOperateLog(member, logEnum.getType(), logEnum.getSubType(), beforeRole, afterRole);
    }

    /**
     * 添加成员操作日志
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addMemberOperateLog(PrepareMemberEntity member,
                                       PrepareOperateTypeEnum operateType,
                                       PrepareSubOperateTypeEnum operateSubType,
                                       PrepareMemberRoleEnum beforeRole,
                                       PrepareMemberRoleEnum afterRole) {
        UserBaseInfoDO user = Optional.ofNullable(commonManager.findUserById(member.getUserId()))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("用户不存在"));
        return addMemberOperateLog(
            member.getPrepareId(), Currents.userId(),
            operateType, operateSubType,
            member.getId(), user.getNickname(), beforeRole, afterRole);
    }

    /**
     * 添加成员操作日志
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addMemberOperateLog(Long prepareId,
                                       Long operator,
                                       PrepareOperateTypeEnum operateType,
                                       PrepareSubOperateTypeEnum operateSubType,
                                       Long targetId,
                                       String targetName,
                                       PrepareMemberRoleEnum beforeRole,
                                       PrepareMemberRoleEnum afterRole) {
        return addLog(
            prepareId, PrepareTypeEnum.MEMBER,
            operator, operateType, operateSubType,
            targetId, targetName, beforeRole, afterRole);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addQuestionOperateLog(PrepareQuestionBankEntity entity, PrepareOperateTypeEnum operateType, PrepareSubOperateTypeEnum operateSubType) {
        return addQuestionOperateLog(
            entity.getPrepareId(), Currents.userId(), operateType, operateSubType,
            entity.getId(), entity.getName()
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addQuestionOperateLog(PrepareQuestionBankEntity entity, PrepareOperateLogEnum logEnum) {
        return addQuestionOperateLog(
            entity.getPrepareId(), Currents.userId(), logEnum.getType(), logEnum.getSubType(),
            entity.getId(), entity.getName()
        );
    }

    /**
     * 添加试题操作日志
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addQuestionOperateLog(Long prepareId,
                                         Long operator,
                                         PrepareOperateTypeEnum operateType,
                                         PrepareSubOperateTypeEnum operateSubType,
                                         Long targetId,
                                         String targetName) {
        return addLog(
            prepareId, PrepareTypeEnum.QUESTION_BANK,
            operator, operateType, operateSubType,
            targetId, targetName, null, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addLog(Long prepareId,
                          PrepareTypeEnum type,
                          Long operator,
                          PrepareOperateTypeEnum operateType,
                          PrepareSubOperateTypeEnum operateSubType,
                          Long targetId,
                          String targetName,
                          PrepareMemberRoleEnum beforeRole,
                          PrepareMemberRoleEnum afterRole) {
        // 获取操作用户信息
        UserBaseInfoDO operatorUser = Lambdas.ofNull(commonManager.findUserById(operator), "用户不存在");
        PrepareEntity prepare = Optional.ofNullable(commonManager.findPrepareById(prepareId))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("remind.content.prepare.not.blank")));
        // 获取操作日志枚举
        PrepareOperateLogEnum logEnum = PrepareOperateLogEnum.of(operateType, operateSubType)
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("获取操作日志枚举失败"));
        LocalDateTime deadlineTime = null;
        // 删除文件，可以30天内恢复
        if (Objects.equals(logEnum, PrepareOperateLogEnum.FILE_DEL)) {
            deadlineTime = LocalDateTime.now().plusDays(PrepareConstant.RECOVERY_DEL_FILE_DAYS);
        }
        // 获取内容
        String content = getContent(logEnum, prepare.getName(), type, targetName, operatorUser, beforeRole, afterRole);
        // 封装类
        PrepareOperateLogEntity log = new PrepareOperateLogEntity();
        log.setPrepareId(prepareId);
        log.setType(type);
        log.setOperateType(operateType);
        log.setOperateSubType(operateSubType);
        log.setTargetId(targetId);
        log.setTargetName(targetName);
        log.setOperator(operatorUser.getId());
        log.setOperateName(operatorUser.getNickname());
        log.setOperateAvatar(operatorUser.getAvatar());
        log.setTitle(content);
        log.setOperateContent(content);
        log.setDeadlineTime(deadlineTime);
        log.setBeforeRole(beforeRole);
        log.setAfterRole(afterRole);
        return save(log);
    }

    private static String getContent(PrepareOperateLogEnum logEnum,
                                     String prepareName,
                                     PrepareTypeEnum type,
                                     String targetName,
                                     UserBaseInfoDO operatorUser,
                                     PrepareMemberRoleEnum beforeRole,
                                     PrepareMemberRoleEnum afterRole) {
        String content = null;
        switch (logEnum) {
            case FILE_ADD:
            case FILE_EDIT:
            case FILE_DEL:
                content = logEnum.format(type.getDescribe(), targetName);
                break;
            case MEMBER_ADD:
                content = logEnum.format(operatorUser.getNickname(), targetName, prepareName);
                break;
            case MEMBER_CHANGE:
                content = logEnum.format(targetName, beforeRole.getDescribe(), afterRole.getDescribe());
                break;
            case MEMBER_QUIT:
            case MEMBER_REMOVE:
                content = logEnum.format(targetName, prepareName);
                break;
            case QUESTION_ADD:
            case QUESTION_EDIT:
            case QUESTION_DEL:
                content = logEnum.format(targetName);
                break;
        }
        return content;
    }

}
